# !/usr/bin/env python
# coding: utf-8
import random
import math
import time
import requests
import os
import threading
import json
import traceback
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib import parse
from multiprocessing import Process


class PressTest(object):
    def __init__(self, base_log, base_lat, THREAD_NUM):
        # 测试http://10.8.0.255/
        self.url = 'http://distance.cm/count_service'
        self.base_log = base_log
        self.base_lat = base_lat
        self.THREAD_NUM = THREAD_NUM
        self.radius = 100000
        self.data = None
        self.store_location = None
        self.lessThen500 = []
        self.moreThen500 = []
        self.moreThen1000 = []
        self.response = None

    def generate_random_gps(self):
        radius_in_degrees = self.radius / 111300
        u = float(random.uniform(0.0, 1.0))
        v = float(random.uniform(0.0, 1.0))
        w = radius_in_degrees * math.sqrt(u)
        t = 2 * math.pi * v
        x = w * math.cos(t)
        y = w * math.sin(t)
        longitude = y + self.base_log
        latitude = x + self.base_lat
        return longitude, latitude

    def get_response_time(self):
        pt.generate_random_gps()
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        user_location = [str(self.base_log), str(self.base_lat)]
        self.store_location = [{"longitude": "114.12597366", "dimension": "22.54615355", "uid": 1},
                               {"longitude": "114.22597366", "dimension": "22.54615355", "uid": 2},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 3},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 4},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 5},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 6},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 7},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 8},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 9},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 10},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 11},
                               {"longitude": "114.82597366", "dimension": "22.54605355", "uid": 12},
                               {"longitude": "114.42597366", "dimension": "22.54685355", "uid": 13},
                               {"longitude": "114.72597366", "dimension": "22.54665355", "uid": 14},
                               {"longitude": "114.72597366", "dimension": "22.54605355", "uid": 15}]
        for num in range(15):
            longitude, latitude = pt.generate_random_gps()
            self.store_location[num]['longitude'] = str(longitude)
            self.store_location[num]['dimension'] = str(latitude)
        self.data = {
            "user_location": str(user_location).replace("'", '"'),
            "store_location": str(self.store_location).replace("'", '"')
        }
        try:
            self.response = requests.post(self.url, data=self.data, headers=headers)
        except Exception:
            traceback.print_exc()
            time.sleep(30)
        else:
            print(f"{self.response.elapsed.microseconds / 1000}ms")
            if self.response.elapsed.microseconds / 1000 < 500:
                self.lessThen500.append(self.response.elapsed.microseconds / 1000)
            if 500 < self.response.elapsed.microseconds / 1000 < 1000:
                self.moreThen500.append(self.response.elapsed.microseconds / 1000)
            if self.response.elapsed.microseconds / 1000 > 1000:
                self.moreThen1000.append(self.response.elapsed.microseconds / 1000)
            try:
                result = self.response.json()
            except Exception:
                traceback.print_exc()
                time.sleep(30)
                exit()
            else:
                if self.response.elapsed.microseconds / 1000 < 100:
                    print(json.dumps(self.response.json(), indent=4, ensure_ascii=False, sort_keys=','))
                if len(result['data']) == 0:
                    print("返回数据为空！")
                    # print(json.dumps(self.response.json(), indent=4, ensure_ascii=False, sort_keys=','))

    @staticmethod
    def get_NumberOfLogicalProcessors():
        result = os.popen('wmic cpu get NumberOfLogicalProcessors').read()
        cpuNum = str(result).strip("NumberOfLogicalProcessors").strip()
        return int(cpuNum) * 2

    def run(self):
        with ThreadPoolExecutor(max_workers=pt.get_NumberOfLogicalProcessors()) as t:
            startTime = time.time()
            Threads = []
            for i in range(self.THREAD_NUM):
                obj = t.submit(pt.get_response_time())
                Threads.append(obj)
                if i == 0:
                    print(f"请求坐标为：\n{self.store_location}")
                    print(f"返回的数据为：\n{json.dumps(self.response.json(), indent=4, ensure_ascii=False, sort_keys=',')}")
            # for i in range(self.THREAD_NUM):
            #     t = threading.Thread(target=pt.get_response_time(), name="T" + str(i))
            #     t.setDaemon(True)
            #     Threads.append(t)
            # for t in Threads:
            #     t.start()
            # for t in Threads:
            #     t.join()
            endTime = time.time()
            print('================压测结果================')
            print('url:', self.url)
            print("任务数量:", self.THREAD_NUM)
            print("总耗时(秒):", endTime - startTime)
            print(f"并发{self.THREAD_NUM}次，小于500毫秒的请求的次数共 {len(self.lessThen500)} 次")
            print(f"并发{self.THREAD_NUM}次，500到1000毫秒的请求的次数共 {len(self.moreThen500)} 次")
            print(f"并发{self.THREAD_NUM}次，超过1000毫秒的请求的次数共 {len(self.moreThen1000)} 次")


if __name__ == '__main__':
    while True:
        THREAD_NUM = str(input("请输入要并发的次数："))
        if THREAD_NUM == '':
            print("输入错误，请重新输入~")
            continue
        elif len(THREAD_NUM) >= 4:
            print("输入错误，请重新输入~")
            continue
        else:
            try:
                pt = PressTest(base_log=114.12597366, base_lat=25.030821208993096, THREAD_NUM=int(THREAD_NUM))
            except Exception:
                traceback.print_exc()
                print("输入错误，请重新输入~")
                continue
            else:
                pt.run()
                time.sleep(60)
                break
